<template>
  <div>
    <div class="vix-list-header">
      <dynamics-filter
        :setting="querySetting"
        :loading="listQuery.loading"
        button-inline
        :wrapper-width="200"
        @query="handleQuery"
      />
    </div>
    <div class="vix-list-body">
      <div class="vix-operate-wrap">
        <div class="vix-operate-section vix-operate-section-right">
          <u-button type="text" class="vix-operate-button" @click="handleAdd">
            <u-icon type="add-circle-outline" />新建用户
          </u-button>
        </div>
      </div>
      <div class="vix-list-content">
        <u-table
          ref="table"
          :columns="columns"
          :data="listData"
          :loading="listQuery.loading"
          :border="false"
          row-key="id"
          show-pagination
          :pagination="{
            total: listQuery.total,
            current: listQuery.currentPage,
            pageSize: listQuery.pageSize,
            showSizer: true,
            showTotal: true
          }"
          @change="handleTableChange"
        >
          <template #roles="{ row }">
            {{ row.roleNames }}
          </template>
          <template #department="{ row }">
            {{ getDepartment(row.departmentId, departmentOptions) }}
          </template>
          <template #createTime="{ row }">
            {{ parseTime(row.createDate, 'YYYY-MM-DD HH:mm:ss') }}
          </template>
          <template #status="{ row }">
            <span
              class="status-color"
              :class="
                getEnumDisplay(row.vaildOrNot, statusOptions, {
                  value: 'value',
                  label: 'class'
                })
              "
            >
              {{ getEnumDisplay(row.vaildOrNot, statusOptions) }}
            </span>
          </template>
          <template #action="{ row }">
            <u-tooltip v-if="row.vaildOrNot === 1" title="禁用">
              <u-link
                type="primary"
                :underline="false"
                class="m-l-1"
                @click="handleForbit(row)"
              >
                <u-icon custom="aic-icon aic-forbit" :size="14" />
              </u-link>
            </u-tooltip>
            <u-tooltip v-else title="启用">
              <u-link
                type="primary"
                :underline="false"
                class="m-l-1"
                @click="handleForbit(row)"
              >
                <u-icon custom="aic-icon aic-start" :size="14" />
              </u-link>
            </u-tooltip>
            <u-tooltip title="编辑">
              <u-link
                type="primary"
                :underline="false"
                class="m-l-1"
                @click.stop="handleEdit(row)"
              >
                <u-icon type="edit" :size="14" />
              </u-link>
            </u-tooltip>
            <u-tooltip title="重置密码">
              <u-link
                type="primary"
                :underline="false"
                class="m-l-1"
                @click="handleResetPassword(row)"
              >
                <u-icon custom="aic-icon aic-reset-passward" :size="14" />
              </u-link>
            </u-tooltip>
          </template>
        </u-table>
      </div>
    </div>
    <edit-drawer
      v-model:visible="editShow"
      :title="editTitle"
      show-submit
      :submit-loading="saveLoading"
      @submit="handleSave"
      @close="handleClose"
      @cancel="handleClose"
    >
      <dynamics-form ref="formRef" :model="editData" :setting="editSetting">
        <template #password>
          <u-input
            ref="pwd"
            v-model="editData.password"
            placeholder="请输入密码"
            :style="{ width: '136px' }"
            class="m-r-1"
          />
          <u-button @click="handleRandomPassword">
            生成随机密码
          </u-button>
        </template>
        <template #department>
          <u-cascader
            v-model="editData.department"
            :options="editDepartmentData"
            placeholder="请选择部门"
            :change-on-select="editData.userType !== 1"
          />
        </template>
      </dynamics-form>
    </edit-drawer>
    <reset-passward-dialog ref="resetPasswardDialog" />
  </div>
</template>

<script>
import { computed, reactive, ref } from 'vue'
// import { useStore } from 'vuex';
import {
  DynamicsFilter,
  DynamicsForm,
  EditDrawer,
  hooks,
  libs,
  message
} from '@bairong/vix'
import {
  getUserListApi,
  getRoleOptionsApi,
  getDepartmentOptionsApi,
  updateUserApi,
  updateUserStatusApi,
  addUserApi,
  checkUserNameApi
} from '@api/author'
import { statusOptions } from '@/libs/data/enums'
import config from '@/config/config'
import ResetPasswardDialog from './dialog/ResetPasswardDialog.vue'

const { getEnumDisplay, parseTime } = libs.conversion
const { usePageList } = hooks

// 递归转换
function deepBuildDepartmentTree(parentId, source) {
  const list = source
    .filter(x => x.superId === parentId)
    .map(x => ({
      value: x.id,
      label: x.departmentName,
      children: []
    }))
  if (list.length > 0) {
    list.forEach(n => {
      n.children = deepBuildDepartmentTree(n.value, source)
    })
  }
  return list
}
// 部门数据转到树结构
function transformDepartmentOption(source, hasRoot = true) {
  if (hasRoot) {
    return [
      {
        value: 0,
        label: config.companyName,
        children: deepBuildDepartmentTree(0, source)
      }
    ]
  }
  return deepBuildDepartmentTree(0, source)
}

function getDepartment(val, option) {
  if (val === 0) {
    return config.companyName
  }
  return getEnumDisplay(val, option, {
    value: 'id',
    label: 'departmentName'
  })
}
// 生成随机密码
function randomString(len = 32) {
  const $chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKMNOPQRSTUVWXYZ1234567890'
  const maxPos = $chars.length
  let pwd = ''
  for (let i = 0; i < len; i += 1) {
    pwd += $chars.charAt(Math.floor(Math.random() * maxPos))
  }
  return pwd
}

export default {
  name: 'UserManage',
  components: {
    DynamicsFilter,
    DynamicsForm,
    EditDrawer,
    ResetPasswardDialog
  },
  filters: {},
  setup() {
    // 存储角色/用户类型
    const roleTypeOptions = ref([])
    // 存储角色下拉数据（全部），在查询项配置remoteMethod中获取
    const roleOptions = ref([])
    // 存储部门下拉数据（全部），在查询项配置remoteMethod中获取
    const departmentOptions = ref([])

    // ====== list ======
    // #region

    // 查询项配置
    const querySetting = ref([
      {
        name: 'key',
        label: '姓名/用户名',
        placeholder: '输入姓名或用户名',
        type: 'input'
      },
      {
        name: 'departmentId',
        label: '部门',
        type: 'cascader',
        options: [],
        placeholder: '选择部门',
        props: {
          changeOnSelect: true
        },
        remoteMethod: () => new Promise(reslove => {
          getDepartmentOptionsApi().then(data => {
            departmentOptions.value = data
            const rst = transformDepartmentOption(data)
            reslove(rst)
          })
        }),
        convert: {
          func: val => {
            // 选择到总公司，给接口传空
            if (val.length === 1 && val[0] === 0) {
              return ''
            }
            // 否则逗号分隔
            return val[val.length - 1]
          }
        }
      },
      {
        name: 'roleId',
        label: '角色',
        type: 'select',
        placeholder: '选择角色',
        options: [],
        remoteMethod: () => new Promise(reslove => {
          getRoleOptionsApi().then(data => {
            roleOptions.value = data
            reslove(data)
          })
        })
      }
    ])

    const appendParams = reactive({
      // 查询部门时，查包含所有子部门的数据
      flag: 1
    })
    // 列表配置
    const columns = ref([
      {
        title: '用户名',
        minWidth: 100,
        key: 'userName',
        fixed: 'left'
      },
      {
        title: '姓名',
        minWidth: 100,
        key: 'realName',
        fixed: 'left'
      },
      {
        title: '角色',
        minWidth: 140,
        key: 'roles',
        slot: 'roles'
      },
      {
        title: '部门',
        minWidth: 140,
        key: 'department',
        slot: 'department'
      },
      {
        title: '电话号码',
        minWidth: 140,
        key: 'phone'
      },
      {
        title: '邮箱',
        minWidth: 160,
        key: 'email'
      },

      {
        title: '创建时间',
        minWidth: 150,
        key: 'createTime',
        slot: 'createTime'
      },
      {
        title: '用户状态',
        minWidth: 100,
        key: 'status',
        slot: 'status'
      },
      {
        title: '操作',
        width: 90,
        fixed: 'right',
        key: 'action',
        slot: 'action'
      }
    ])

    const {
      listData,
      listQuery,
      getList,
      handleQuery,
      handlePageChange
    } = usePageList({
      getListApi: getUserListApi,
      appendParams
    })

    getList()

    const handleTableChange = pagination => {
      handlePageChange(pagination.current, pagination.pageSize)
    }

    const handleForbit = row => {
      updateUserStatusApi({ id: row.id }).then(() => {
        message.success('操作成功')
        getList()
      })
    }
    // #endregion

    // ======= edit =======
    // #region
    const operateType = ref('add')
    const editTitle = computed(() => (operateType.value === 'add' ? '新建用户' : '编辑用户'))

    const initModel = () => ({
      userName: '',
      realName: '',
      password: '',
      phone: '',
      email: '',
      roleIds: [],
      department: []
    })
    // 编辑时记录原名，重名判断不判断自己
    const originName = ref('')
    // 编辑表单数据
    const editData = ref(initModel())
    // 新建、编辑部门列表，根据角色类型变换
    const editDepartmentData = ref([])
    const editSetting = ref([])
    // const store = useStore();
    const defaultRule = {
      pattern: /^(((0\d{2,3}-)?\d{1,8})|(1[23456789]\d{9}))$/,
      message: '请输入正确的电话号码',
      trigger: 'blur'
    }
    const phoneRules = [
      defaultRule,
      {
        required: true,
        message: '人工业务相关人员必须配置手机号用于人工外呼'
      }
    ]
    // 编辑表单配置
    editSetting.value = [
      {
        name: 'userName',
        label: '用户名',
        placeholder: '请输入用户名',
        type: 'input',
        disabled: () => operateType.value === 'edit',
        rules: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
          {
            validator: (rule, value, callback) => {
              const pattern = /^[A-z.!@#$%^&*?0-9_-]{6,20}$/.test(value)
              if (value && value === originName.value) {
                callback()
              } else if (pattern) {
                checkUserNameApi({ key: value })
                  .then(res => {
                    if (res) {
                      callback()
                    } else {
                      callback(new Error('用户名重复'))
                    }
                  })
                  .catch(err => {
                    callback(new Error(err))
                  })
              } else {
                callback(new Error('仅支持6-20位英文、数字、字符.!@#$%^&*?_-'))
              }
            },
            trigger: 'blur'
          }
        ]
      },
      {
        name: 'realName',
        label: '姓名',
        placeholder: '请输入姓名',
        type: 'input',
        rules: [
          {
            required: true,
            whitespace: true,
            message: '请输入姓名',
            trigger: 'blur'
          },
          {
            pattern: /^[\u4e00-\u9fa5A-z0-9·_-]{2,20}$/,
            message: '仅支持2-20位中文、英文、数字、字符·_-',
            trigger: 'blur'
          }
        ]
      },
      {
        name: 'password',
        label: '初始密码',
        placeholder: '请输入初始密码',
        type: 'slot',
        slot: 'password',
        show: () => operateType.value === 'add',
        rules: [
          {
            required: true,
            whitespace: true,
            message: '请设置初始密码',
            trigger: 'blur'
          },
          {
            pattern: /^[a-zA-Z0-9-*/+.~!@#$%^&*()]{6,20}$/,
            message: '仅支持6-20位英文、数字、字符-*/+.~!@#$%^&*()',
            trigger: 'blur'
          }
        ]
      },
      {
        name: 'phone',
        label: '电话号码',
        placeholder: '请输入电话号码',
        tips: '人工业务相关人员必须配置电话号码',
        type: 'input'
      },
      {
        name: 'email',
        label: '邮箱',
        placeholder: '请输入邮箱',
        type: 'input',
        rules: [
          {
            max: 30,
            message: '请输入不超过30位字符的有效邮箱',
            trigger: 'blur'
          },
          { validator: libs.validation.validateEmail, trigger: 'blur' }
        ]
      },
      {
        name: 'roleIds',
        label: '角色',
        type: 'select',
        props: {
          multiple: true
        },
        options: [],
        rules: [
          {
            required: true,
            type: 'array',
            message: '请选择角色',
            trigger: 'change'
          }
        ]
      },
      {
        name: 'department',
        label: '部门',
        type: 'slot',
        slot: 'department',
        rules: [
          {
            required: true,
            type: 'array',
            message: '请选择部门',
            trigger: 'change'
          }
        ]
      }
    ]

    // 保存loading
    const saveLoading = ref(false)
    // 新建抽屉开关
    const editShow = ref(false)
    const formRef = ref(null)

    const setFormOptions = () => {
      let range = []
      // 控制角色
      range = [1, 2]
      // 只能选人工部门
      editDepartmentData.value = transformDepartmentOption(
        departmentOptions.value.filter(x => x.departmentType === 1),
        false
      )
      // 根据用户类型，更换角色可选值
      const roleSetting = editSetting.value.find(x => x.name === 'roleIds')
      roleSetting.options = roleOptions.value.filter(x => range.includes(x.type))

      const phoneSetting = editSetting.value.find(x => x.name === 'phone')
      phoneSetting.rules = phoneRules
    }
    // 新建事件
    const handleAdd = () => {
      getRoleOptionsApi().then(data => {
        roleOptions.value = data
        setFormOptions()
        operateType.value = 'add'
        editData.value = initModel()
        editShow.value = true
      })
    }

    // 获取部门路径，为级联组件提供数据
    const getDepartmentPath = (departmentId, hasRoot) => {
      // 部门ID为0.说明部门配到了公司
      if (departmentId === 0) {
        return [0]
      }
      const findParent = (id, _list) => {
        const find = departmentOptions.value.find(x => x.id === id)
        if (find) {
          _list.unshift(find.id)
          if (find.superId !== 0) {
            findParent(find.superId, _list)
          } else if (hasRoot) {
            _list.unshift(0)
          }
        }
      }
      const list = []
      findParent(departmentId, list)
      return list
    }

    const handleEdit = row => {
      operateType.value = 'edit'
      const {
        id,
        userName,
        realName,
        phone,
        email,
        type,
        roleIds,
        departmentId
      } = row
      originName.value = userName
      editData.value = {
        id,
        userName,
        realName,
        phone,
        email,
        roleIds: roleIds.split(',').map(x => parseInt(x, 10)),
        department: getDepartmentPath(departmentId, type > 2)
      }
      // 根据用户角色，调整相关内容
      editShow.value = true
    }

    const handleClose = () => {
      editShow.value = false
      formRef.value.resetFields()
      // editData.value = initModel();
    }

    // 生成随机密码
    const handleRandomPassword = () => {
      const length = 8
      const passReg = /^(?=.*[0-9].*)(?=.*[A-Z].*)(?=.*[a-z].*).{8,}$/
      function newRandPass() {
        const randPass = randomString(length)
        if (!passReg.test(randPass)) {
          return newRandPass()
        }
        return randPass
      }

      editData.value.password = newRandPass()
    }

    const handleSave = () => {
      formRef.value
        .validate()
        .then(() => {
          saveLoading.value = true
          const {
            id,
            realName,
            userName,
            password,
            department,
            phone,
            email,
            roleIds,
            remark
          } = editData.value
          const params = {
            id,
            realName,
            userName,
            departmentId: department[department.length - 1],
            phone,
            email,
            roleIds: roleIds.join(','),
            remark
          }
          params.password = password ? libs.tools.md5(password) : undefined;
          (operateType.value === 'add' ? addUserApi : updateUserApi)(params)
            .then(() => {
              saveLoading.value = false
              handleClose()
              message.success('保存成功')
              getList()
            })
            .catch(err => {
              saveLoading.value = false
              message.error(err)
            })
        })
        .catch(() => {})
    }

    // #endregion

    const resetPasswardDialog = ref(null)

    // 重置密码
    const handleResetPassword = data => {
      resetPasswardDialog.value.show(data)
    }

    return {
      // list
      querySetting,
      columns,
      listData,
      listQuery,
      handleQuery,
      handleTableChange,
      handleForbit,
      // edit
      editTitle,
      formRef,
      editData,
      editSetting,
      editDepartmentData,
      saveLoading,
      editShow,
      handleAdd,
      handleEdit,
      handleSave,
      handleClose,
      handleRandomPassword,
      resetPasswardDialog,
      handleResetPassword,
      // enum filter
      getDepartment,
      getEnumDisplay,
      parseTime,
      statusOptions,
      roleTypeOptions,
      roleOptions,
      departmentOptions
    }
  }
}
</script>
